package ar.fgsoruco.opencv4.factory.imagefilter

import org.opencv.core.Mat
import org.opencv.core.MatOfByte
import org.opencv.core.Size
import org.opencv.imgcodecs.Imgcodecs
import org.opencv.imgproc.Imgproc
import java.io.FileInputStream
import java.io.InputStream
import io.flutter.plugin.common.MethodChannel

import org.opencv.core.Core


class ErodeFactory {
    companion object{

        fun process(pathType: Int,pathString: String, data: ByteArray, kernelSize: ArrayList<Double>, result: MethodChannel.Result) {
            when (pathType){
                1 -> result.success(erodeS(pathString, kernelSize))
                2 -> result.success(erodeB(data, kernelSize))
                3 -> result.success(erodeB(data, kernelSize))
            }
        }

        //Module: Image Filtering
        private fun erodeS(pathString: String, kernelSize: ArrayList<Double>): ByteArray? {
            val inputStream: InputStream = FileInputStream(pathString.replace("file://", ""))
            val data: ByteArray = inputStream.readBytes()

            try {
                var byteArray = ByteArray(0)
                val dst = Mat()
                // Decode image from input byte array
                val filename = pathString.replace("file://", "")
                val src = Imgcodecs.imread(filename)

                // Preparing the kernel matrix object
                val kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT,
                        Size((kernelSize[0] * kernelSize[1] + 1),
                                (kernelSize[0] * kernelSize[1] + 1)))

                // Convert the image to Gray
                Imgproc.erode(src, dst, kernel)

                // instantiating an empty MatOfByte class
                val matOfByte = MatOfByte()
                // Converting the Mat object to MatOfByte
                Imgcodecs.imencode(".jpg", dst, matOfByte)
                byteArray = matOfByte.toArray()
                return byteArray
            } catch (e: java.lang.Exception) {
                println("OpenCV Error: $e")
                return data
            }
        }


        //Module: Image Filtering
        private fun erodeB(data: ByteArray, kernelSize: ArrayList<Double>): ByteArray? {

            try {
                var byteArray = ByteArray(0)
                val dst = Mat()
                // Decode image from input byte array
                val src = Imgcodecs.imdecode(MatOfByte(*data), Imgcodecs.IMREAD_UNCHANGED)

                // Preparing the kernel matrix object
                val kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT,
                        Size((kernelSize[0] * kernelSize[1] + 1),
                                (kernelSize[0] * kernelSize[1] + 1)))

                // Convert the image to Gray
                Imgproc.erode(src, dst, kernel)

                // instantiating an empty MatOfByte class
                val matOfByte = MatOfByte()
                // Converting the Mat object to MatOfByte
                Imgcodecs.imencode(".jpg", dst, matOfByte)
                byteArray = matOfByte.toArray()
                return byteArray
            } catch (e: java.lang.Exception) {
                println("OpenCV Error: $e")
                return data
            }

        }

    }
}


class DeleteBlackFactory {
    companion object {

        fun process(pathType: Int, pathString: String, data: ByteArray, kernelSize: ArrayList<Double>, result: MethodChannel.Result) {
            when (pathType) {
                1 -> result.success(deleteBlackS(pathString, kernelSize))
                2 -> result.success(deleteBlackB(data, kernelSize))
                3 -> result.success(deleteBlackB(data, kernelSize))
            }
        }

        private fun deleteBlackS(pathString: String, kernelSize: ArrayList<Double>): ByteArray? {
            val inputStream: InputStream = FileInputStream(pathString.replace("file://", ""))
            val data: ByteArray = inputStream.readBytes()
            try {
                var byteArray = ByteArray(0)
                val dst = Mat()
                val filename = pathString.replace("file://", "")
                val src = Imgcodecs.imread(filename)
                // 灰度
                Imgproc.cvtColor(src, dst, Imgproc.COLOR_RGB2GRAY)
//                val n = 15
                //做最大滤波(膨胀)，得到maxFilterMat_A
//                val element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, Size(n.toDouble(), n.toDouble()))
                val element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT,
                        Size((kernelSize[0] * kernelSize[1] + 1),
                                (kernelSize[0] * kernelSize[1] + 1)))
                val maxFilterMat_A = Mat()
                Imgproc.dilate(dst, maxFilterMat_A, element)
                //再对maxFilterMat_A做最小化滤波（腐蚀）
                val minFilterMat_B = Mat()
                Imgproc.erode(maxFilterMat_A, minFilterMat_B, element)
                //(先最大再最小滤波) - 原灰度图
                val calcMat = Mat()
                Core.subtract(minFilterMat_B, dst, calcMat)
                //取反，得到白底黑字
                Core.bitwise_not(calcMat, calcMat)
                val normalizeMat = Mat()
                Core.normalize(calcMat, normalizeMat, 0.0, 255.0, Core.NORM_MINMAX)
                // normalizeMat
                val matOfByte = MatOfByte()
                Imgcodecs.imencode(".jpg", normalizeMat, matOfByte)
                byteArray = matOfByte.toArray()
                return byteArray
            } catch (e: Exception) {
                return data
            }

//            val bitmapNew = b.copy(b.config, b.isMutable)
//            val src = Mat()
//            Utils.bitmapToMat(bitmapNew, src) // turn bitmap into mat
//            val dst = Mat()
//            Imgproc.cvtColor(src, dst, Imgproc.COLOR_RGB2GRAY) //灰色
//            val n = 15
//            //做最大滤波(膨胀)，得到maxFilterMat_A
//            val element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, Size(n.toDouble(), n.toDouble()))
//            val maxFilterMat_A = Mat()
//            Imgproc.dilate(dst, maxFilterMat_A, element)
//            //再对maxFilterMat_A做最小化滤波（腐蚀）
//            val minFilterMat_B = Mat()
//            Imgproc.erode(maxFilterMat_A, minFilterMat_B, element)
//            //(先最大再最小滤波) - 原灰度图
//            val calcMat = Mat()
//            Core.subtract(minFilterMat_B, dst, calcMat)
//            //取反，得到白底黑字
//            Core.bitwise_not(calcMat, calcMat)
//            val normalizeMat = Mat()
//            Core.normalize(calcMat, normalizeMat, 0.0, 255.0, Core.NORM_MINMAX)
//            Utils.matToBitmap(normalizeMat, bitmapNew)
//            return bitmapNew
        }

        private fun deleteBlackB(data: ByteArray, kernelSize: ArrayList<Double>): ByteArray? {
            try {
                var byteArray = ByteArray(0)
                val dst = Mat()
                // Decode image from input byte array
                val src = Imgcodecs.imdecode(MatOfByte(*data), Imgcodecs.IMREAD_UNCHANGED)

                // Preparing the kernel matrix object
                val kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT,
                        Size((kernelSize[0] * kernelSize[1] + 1),
                                (kernelSize[0] * kernelSize[1] + 1)))

                // Convert the image to Gray
                Imgproc.cvtColor(src, dst, Imgproc.COLOR_RGB2GRAY)

                val element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT,
                        Size((kernelSize[0] * kernelSize[1] + 1),
                                (kernelSize[0] * kernelSize[1] + 1)))
                val maxFilterMat_A = Mat()
                Imgproc.dilate(dst, maxFilterMat_A, element)
                //再对maxFilterMat_A做最小化滤波（腐蚀）
                val minFilterMat_B = Mat()
                Imgproc.erode(maxFilterMat_A, minFilterMat_B, element)
                //(先最大再最小滤波) - 原灰度图
                val calcMat = Mat()
                Core.subtract(minFilterMat_B, dst, calcMat)
                //取反，得到白底黑字
                Core.bitwise_not(calcMat, calcMat)
                val normalizeMat = Mat()
                Core.normalize(calcMat, normalizeMat, 0.0, 255.0, Core.NORM_MINMAX)
                // normalizeMat
                val matOfByte = MatOfByte()
                Imgcodecs.imencode(".jpg", normalizeMat, matOfByte)
                byteArray = matOfByte.toArray()
                return byteArray
            } catch (e: java.lang.Exception) {
                println("OpenCV Error: $e")
                return data
            }
        }
    }
}

